﻿// (c) Andreas Kreisl
// You are not permitted to use this in any way!

var class_graph_debug = false | global_debug;

function class_graph() {
	// Preferences (Members)
	this.width = 32;
	this.height = 32;
	this.graphdir = 1;

	// Const Values
	this.spaccing = 3;
	this.round = 3;
	this.colordiff = 32;
	this.textsize = 10;

	// Background
	this.Background_Canvas = new Canvas();
	this.Background_Canvas.window = main;
	this.Background_Color = "#707070";
	this.Background_ctx = this.Background_Canvas.getContext( "2d" );

	// Border
	this.Border_Canvas = new Canvas();
	this.Border_Canvas.window = main;
	this.Border_Color = "#000000";
	this.Border_ctx = this.Border_Canvas.getContext( "2d" );
	this.Border_Canvas.orderAbove(this.Background_Canvas);

	// Temp Database
	this.db = new SQLite();
	this.db.open(":memory:");
	this.db.exec("CREATE TABLE graph (g_id int(2), g_nb int(11), g_val int(11));");
	this.db_count = 0;

	// The Graphs
	this.Graph_Canvas = new Array();
	this.Graph_ctx = new Array();
	this.Graph_vOffset = new Array();
	this.Graph_Color = new Array();
	this.Graph_Negative = new Array();
	this.Graph_Text = new Array();
	this.Graph_Max = new Array();

	// All Functions (Methods)
	this.draw = class_graph_draw;
	this.redraw = class_graph_redraw;
	this.add = class_graph_addGraph;
	this.update = class_graph_updateGraph;
	this.saveImageToFile = class_graph_saveImageToFile;
	return true;
}

function class_graph_draw() {
	// Init size
	main.width  = this.width  + 2 * this.spaccing;
	main.height = this.height + 2 * this.spaccing;
	this.Background_Canvas.width  = main.width;
	this.Background_Canvas.height = main.height;
	this.Border_Canvas.width      = main.width;
	this.Border_Canvas.height     = main.height;
	for(i=0;i<this.Graph_Canvas.length;i++) {
		this.Graph_Canvas[i].width      = main.width;
		this.Graph_Canvas[i].height     = main.height;
		this.Graph_Text[i].vOffset = this.spaccing + (this.height / 2) + (((i+1) - (this.Graph_Canvas.length/2)) * this.textsize) - 2;
		if(this.graphdir==1) {
			this.Graph_Text[i].hOffset = this.spaccing + this.width -2;
			this.Graph_Text[i].hAlign  = "right";
		} else {
			this.Graph_Text[i].hOffset = this.spaccing + 2;
			this.Graph_Text[i].hAlign  = "left";
		}
	}

	// Draw Background


	var Background_grad = this.Background_ctx.createLinearGradient( this.spaccing, this.spaccing, this.spaccing + this.width, this.spaccing + this.height);
	Background_grad.addColorStop( 0, class_graph_ColorModify(this.Background_Color,-this.colordiff) );
	Background_grad.addColorStop( 1, class_graph_ColorModify(this.Background_Color, this.colordiff) );
	this.Background_ctx.fillStyle = Background_grad;
	this.Background_ctx.clearRect(0,0,main.width,main.height);
	this.Background_ctx.beginPath();
		this.Background_ctx.moveTo(this.spaccing + this.round,this.spaccing);
		this.Background_ctx.lineTo(this.spaccing + this.width - this.round,this.spaccing);
		this.Background_ctx.quadraticCurveTo(this.spaccing + this.width, this.spaccing,this.spaccing + this.width, this.spaccing + this.round);
		this.Background_ctx.lineTo(this.spaccing + this.width, this.spaccing + this.height - this.round);
		this.Background_ctx.quadraticCurveTo(this.spaccing + this.width,this.spaccing + this.height,this.spaccing + this.width - this.round,this.spaccing + this.height );
		this.Background_ctx.lineTo(this.spaccing + this.round,this.spaccing + this.height);
		this.Background_ctx.quadraticCurveTo(this.spaccing,this.spaccing + this.height, this.spaccing,this.spaccing + this.height - this.round);
		this.Background_ctx.lineTo(this.spaccing,this.spaccing + this.round);
		this.Background_ctx.quadraticCurveTo(this.spaccing,this.spaccing,this.spaccing + this.round,this.spaccing);
	this.Background_ctx.closePath();
	this.Background_ctx.fill();

	// Draw Border
	this.Border_ctx.lineWidth = 1.4;
	this.Border_ctx.lineJoin = "round";
	this.Border_ctx.strokeStyle = this.Border_Color;
	this.Border_ctx.clearRect(0,0,main.width,main.height);
	this.Border_ctx.beginPath();
		this.Border_ctx.moveTo(this.spaccing + this.round,this.spaccing);
		this.Border_ctx.lineTo(this.spaccing + this.width - this.round,this.spaccing);
		this.Border_ctx.quadraticCurveTo(this.spaccing + this.width, this.spaccing,this.spaccing + this.width, this.spaccing + this.round);
		this.Border_ctx.lineTo(this.spaccing + this.width, this.spaccing + this.height - this.round);
		this.Border_ctx.quadraticCurveTo(this.spaccing + this.width,this.spaccing + this.height,this.spaccing + this.width - this.round,this.spaccing + this.height );
		this.Border_ctx.lineTo(this.spaccing + this.round,this.spaccing + this.height);
		this.Border_ctx.quadraticCurveTo(this.spaccing,this.spaccing + this.height, this.spaccing,this.spaccing + this.height - this.round);
		this.Border_ctx.lineTo(this.spaccing,this.spaccing + this.round);
		this.Border_ctx.quadraticCurveTo(this.spaccing,this.spaccing,this.spaccing + this.round,this.spaccing);
	this.Border_ctx.closePath();
	this.Border_ctx.stroke();

	// Clear all Graphs
	for(i=0;i<this.Graph_Canvas.length;i++)
		this.Graph_ctx[i].clearRect(0,0,main.width,main.height);

	return true;
}

function class_graph_redraw() {
	// Temp Variables, there could be optimization potetial
	var Background_grad;
	var db_res;
	var db_all;
	var db_row;
	var i;
	var j;
	var base;
	var h;
	var m;

	// Loop throu all Graphs
	for(i=0;i<this.Graph_Canvas.length;i++) {
		this.Graph_ctx[i].clearRect(0,0,main.width,main.height);

		Background_grad = this.Graph_ctx[i].createLinearGradient( this.spaccing, this.spaccing, this.spaccing + this.width, this.spaccing + this.height);
		Background_grad.addColorStop( 0, class_graph_ColorModify(this.Graph_Color[i],-this.colordiff) );
		Background_grad.addColorStop( 1, class_graph_ColorModify(this.Graph_Color[i], this.colordiff) );
		this.Graph_ctx[i].fillStyle = Background_grad;

		if(this.Graph_Max[i] > 0) {
			m = this.Graph_Max[i];
		} else {
			db_res = this.db.query( "SELECT max(g_val) as m FROM graph WHERE g_id = " + i);
			db_all = db_res.getAll();
			m = db_all[0]["m"];
			if(!m>0) m = this.height;
		}

		// Start and calc vOffset
		this.Graph_ctx[i].beginPath();
		base = this.height * this.Graph_vOffset[i] / 100;

		// Draw base line
		if(this.graphdir==1) {
			this.Graph_ctx[i].moveTo(this.spaccing + this.width - 1,this.spaccing + base)
			this.Graph_ctx[i].lineTo(this.spaccing + 1             ,this.spaccing + base);
		} else {
			this.Graph_ctx[i].moveTo(this.spaccing + 1             ,this.spaccing + base);
			this.Graph_ctx[i].lineTo(this.spaccing + this.width - 1,this.spaccing + base)
		}

		// Query DB and draw the Points
		db_res = this.db.query( "SELECT * FROM graph WHERE g_id = " + i + " ORDER BY g_nb DESC" );
		db_all = db_res.getAll();
		for(j = 1;j <= (this.width - 1) && j <= db_all.length ; j++ ){
			db_row = db_all[(j-1)]["g_val"];
			if(db_row > m) db_row = m;

			if(this.Graph_Negative[i]==1) h = base - (db_row * (this.height-(this.height-base)) / m);
			else h = base + (db_row * (this.height-base) / m);
			if(this.graphdir==1) this.Graph_ctx[i].lineTo(this.spaccing + j,this.spaccing + h);
			else this.Graph_ctx[i].lineTo(this.spaccing + (this.width - j),this.spaccing + h);
		}

		// If the DB contain too less values, draw a zero line for the rest
		for(;j<=(this.width - 1);j++){
			if(this.graphdir==1) this.Graph_ctx[i].lineTo(this.spaccing + j,this.spaccing + base);
			else this.Graph_ctx[i].lineTo(this.spaccing + (this.width - j),this.spaccing + base);
		}

		this.Graph_ctx[i].closePath();
		this.Graph_ctx[i].fill();
	}
	return true;
}

function class_graph_addGraph(vOffset,Color,Negative,Max) {
	// Get next Graph ID
	var j = this.Graph_Canvas.length;

	// Init Canvas + Size
	this.Graph_Canvas[j] = new Canvas();
	this.Graph_Canvas[j].window = main;
	this.Graph_Canvas[j].width  = main.width;
	this.Graph_Canvas[j].height = main.height;
	this.Graph_ctx[j] = this.Graph_Canvas[j].getContext( "2d" );

	this.Graph_vOffset[j] = vOffset;
	this.Graph_Color[j] = Color;
	this.Graph_Negative[j] = Negative;
	this.Graph_Max[j] = Max;
	
	// Init Text
	this.Graph_Text[j] = new Text();
	this.Graph_Text[j].window = main;
	this.Graph_Text[j].font = "Tahoma";
	this.Graph_Text[j].style = "bold";
	this.Graph_Text[j].size = this.textsize;
	this.Graph_Text[j].data = "0"
	this.Graph_Text[j].alignment = "right";
	this.Graph_Text[j].vOffset = this.spaccing + (this.height / 2) + (((j+1) - (this.Graph_Canvas.length/2)) * this.textsize) - 2;
	if(this.graphdir==1) {
		this.Graph_Text[j].hOffset = this.spaccing + this.width -2;
		this.Graph_Text[j].hAlign  = "right";
	} else {
		this.Graph_Text[j].hOffset = this.spaccing + 2;
		this.Graph_Text[j].hAlign  = "left";
	}
	this.Graph_Text[j].color = "#FFFFFF";
	this.Graph_Text[j].orderAbove(this.Border_Canvas);
	this.Graph_Text[j].style.KonShadow = "1px 1px " + class_graph_ColorModify(this.Graph_Color[j],64);


	// Set display Order
	if(j==0) this.Graph_Canvas[j].orderAbove(this.Background_Canvas);
	else     this.Graph_Canvas[j].orderAbove(this.Graph_Canvas[j - 1]);
	this.Border_Canvas.orderAbove(this.Graph_Canvas[j]);

	// Delete all Values for that Graph ID
	this.db.exec("DELETE FROM graph WHERE g_id = " + j);
	return true;
}

function class_graph_updateGraph() {
	if(class_graph_updateGraph.arguments.length>=this.Graph_Canvas.length) {
		// Increase internal DB Counter (just for order, could also be a timestamp)
		this.db_count++;

		// Query throu all Submitted Values
		for(i=0;i<class_graph_updateGraph.arguments.length;i++) {
			this.db.exec("INSERT INTO graph VALUES ("+i+","+this.db_count+","+class_graph_updateGraph.arguments[i]+")");
		}

		// Remove old Datapoints
		this.db.exec("DELETE FROM graph WHERE g_nb < " + (this.db_count - this.width));

		// ReDraw now!
		this.redraw();
	} else {
		if(class_graph_debug) print("class_graph_update - Error, not enough values!");
		return false;
	}
	return true;
}

// === === Help Functions === === === === ===

// Convereter Dec <=> Hex
function d2h(d) {return d.toString(16);}
function h2d(h) {return parseInt(h,16);}

// Make a colore darker/bright
function class_graph_ColorModify(ColorA,cx) {
	var ColorB = "#";
	var tmp;

	tmp = h2d(ColorA.substring(1,3))+cx;
	if(tmp>255)tmp=255;
	if(tmp<0)tmp=0;
	if(tmp>16) ColorB = ColorB + d2h(tmp);
	else ColorB = ColorB + "0" + d2h(tmp);

	tmp = h2d(ColorA.substring(3,5))+cx;
	if(tmp>255)tmp=255;
	if(tmp<0)tmp=0;
	if(tmp>16) ColorB = ColorB + d2h(tmp);
	else ColorB = ColorB + "0" + d2h(tmp);

	tmp = h2d(ColorA.substring(5,7))+cx;
	if(tmp>255)tmp=255;
	if(tmp<0)tmp=0;
	if(tmp>16) ColorB = ColorB + d2h(tmp);
	else ColorB = ColorB + "0" + d2h(tmp);

	return ColorB;
}

function class_graph_saveImageToFile() {
	main.root.saveImageToFile( system.userDesktopFolder + "/"+widget.name+".png", "png" );
	return true;
}

function class_graph_saveImageToFile_old() {
	this.Background_Canvas.saveImageToFile( system.temporaryFolder + "/cg_a.png", "png" );
	this.Border_Canvas.saveImageToFile(     system.temporaryFolder + "/cg_b.png", "png" );
	var i;
	for(i=0;i<this.Graph_Canvas.length;i++) {
		this.Graph_Canvas[i].saveImageToFile(   system.temporaryFolder + "/cg_c_"+i+".png", "png" );
		this.Graph_Text[i].saveImageToFile(     system.temporaryFolder + "/cg_t_"+i+".png", "png" );
	}

	var c    = new Canvas();
	c.width  = main.width;
	c.height = main.height;

	var ctx = c.getContext("2d");
	var img = new Image()

	img.src = system.temporaryFolder + "/cg_a.png";
	ctx.drawImage( img, 0, 0 );

	for(i=0;i<this.Graph_Canvas.length;i++) {
		img.src = system.temporaryFolder + "/cg_c_"+i+".png";
		ctx.drawImage( img, 0, 0 );
	}

	img.src = system.temporaryFolder + "/cg_b.png";
	ctx.drawImage( img, 0, 0 );

	var v;
	for(i=0;i<this.Graph_Canvas.length;i++)
	if(this.Graph_Text[i].visible) {
		img.src = system.temporaryFolder + "/cg_t_"+i+".png";
		v = this.spaccing + (this.height / 2) + (((i+1) - (this.Graph_Canvas.length/2)) * this.textsize) - img.height + 3;
		if(this.graphdir==1) {
			ctx.drawImage( img, this.spaccing + this.width -2 - img.width, v );
		} else {
			ctx.drawImage( img, this.spaccing + 2, v );
		}
	}

	c.saveImageToFile(     system.userDesktopFolder + "/"+widget.name+".png", "png" );

	filesystem.remove(system.temporaryFolder + "/cg_a.png");
	filesystem.remove(system.temporaryFolder + "/cg_b.png");
	for(i=0;i<this.Graph_Canvas.length;i++) {
		filesystem.remove(system.temporaryFolder + "/cg_c_"+i+".png");
		filesystem.remove(system.temporaryFolder + "/cg_t_"+i+".png");
	}
	delete img;
	delete ctx;
	delete c;
	return true;
}